#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
#include "Aritmetico/ICompresor.h"
#include "PPMC/Modelo.h"
#include "PPMC/Contexto.h"
#include "PPMC/PPMC.h"

#define NUMERO_GRUPO "10"

using namespace std;

void showFileSize(const string &archivo)
{
	FILE * pFile;
	float size;

	pFile = fopen (archivo.c_str(),"rb");

	fseek (pFile, 0, SEEK_END);
	size=ftell (pFile);
	fclose (pFile);

	cout << "Tamano del archivo " << archivo << ": ";

	if (size<1024)
	{
		cout << size << " bytes" << endl;
		return;
	}

	size=size/1024;

	if (size<1024)
	{
		cout << size << " KB" << endl;
		return;
	}

	size=size/1024;

	if (size<1024)
	{
		cout << size << " MB" << endl;
		return;
	}

	size=size/1024;

	cout << size << " GB" << endl;
}

/**
 * opciones:
 * 	modo:
 * 		-c comprimir [default]
 * 		-x descomprimir
 *	orden:
 * 		-orden <valor> [default:6]
 * 		valores posibles: [0..inf]
 * 	tipo de modelo:
 * 		-modelo <valor> [default: ie]
 * 		valores posibles:
 * 			'n': Normal
 * 			'eh': Envejecimiento hiperbólico
 * 			'ee': Envejecimiento exponencial
 * 				opciones:
 * 					-termino-independiente <valor> [default: 2]
 * 						valores posibles: [0..inf]
 * 					-factor <valor> [default: 1.1426]
 * 						valores posibles: [0..inf]
 * 			'c': Cuadratico
 * 			'ie': Inicializa ESC en 1 e incremento 3
 * 	mostrar tamaño archivo:
 * 		-mostrar-tamano [defaul: no se muestra]
 * 	nombre del archivo (obligatorio):
 * 		Debe ser el último parámetro.
 */
int TP(int argc, char *argv[])
{
	std::map<string,string> parametros;
    char operacion='c';
    Contexto::Orden orden=6;
    string tipoModelo="ie";
    unsigned short terminoIndependiente=2;
    double factor=1.1426;
    bool mostrarTamano=false;

    try
    {
		for (int i=1; i<(argc-1); i++)
		{
			string parametro(argv[i]);

			if (parametro=="-c"||parametro=="-x")
				operacion=parametro.c_str()[1];
			else if (parametro=="-orden")
				orden=atoi(argv[i+1]);
			else if (parametro=="-modelo")
				tipoModelo=argv[i+1];
			else if (parametro=="-termino-independiente")
				terminoIndependiente=atoi(argv[i+1]);
			else if (parametro=="-factor")
				factor=atof(argv[i+1]);
			else if (parametro=="-mostrar-tamano")
				mostrarTamano=true;
		}

		string nombreArchivo=argv[argc-1];

		ifstream entrada;
		ofstream salida;
		Modelo *modelo;
		ICompresor *ca=NULL;

		if (tipoModelo=="n")
			modelo=new Modelo();
		else if (tipoModelo=="ie")
			modelo=new ModeloInicializaEsc();

		PPMC *ppmc=PPMC::getNewInstance(orden,ca,modelo);

		if (operacion=='c')
		{
			if (mostrarTamano)
				showFileSize(nombreArchivo);

			entrada.open(nombreArchivo.c_str(),ios_base::in);
			if (!entrada.is_open())
				throw string("No se pudo abrir el archivo "+nombreArchivo);

			salida.open((nombreArchivo+"."+NUMERO_GRUPO).c_str(),ios_base::trunc | ios_base::binary);
			if (!salida.is_open())
				throw string("No se pudo abrir el archivo "+nombreArchivo+"."+NUMERO_GRUPO);

			ppmc->comprimir(entrada,salida);
		}
		else
		{
			entrada.open(nombreArchivo.c_str(),ios_base::in | ios_base::binary);
			if (!entrada.is_open())
				throw string("No se pudo abrir el archivo "+nombreArchivo);

			nombreArchivo.replace(nombreArchivo.length()-3,3,"");
			salida.open(nombreArchivo.c_str(),ios_base::trunc);
			if (!salida.is_open())
				throw string("No se pudo abrir el archivo "+nombreArchivo+"."+NUMERO_GRUPO);

			ppmc->descomprimir(entrada,salida);
		}

		entrada.close();
		salida.close();

		PPMC::deleteInstance();

		if (mostrarTamano)
			showFileSize(nombreArchivo+"."+NUMERO_GRUPO);
    }
    catch(string &s)
    {
    	cout << endl << "ERROR: " << s << endl;
    	return 1;
    }
    catch(...)
    {
    	cout << endl << "ERROR: Ha ocurrido un error y no se ha " <<
			"completado la operacion." << endl;
    	return 2;
    }


	return 0;
}

int test(int argc, char *argv[])
{
//	modeloTest();
//
//	contextoTest();
//
//	ppmcTest();

	return 0;
}

int main(int argc, char *argv[])
{
	if ((argc>=2)&&((string(argv[1]))==string("test")))
		return test(argc,argv);
	else
		return TP(argc,argv);
}
